package interceptor;

import annotation.SaInterior;
import annotation.SaInteriorOrElse;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.strategy.SaStrategy;
import common.constant.TokenConstant;
import common.enums.HttpCodeEnum;
import exception.ServiceException;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @Author: 郑国荣
 * @Date: 2024-02-07-9:12
 * @Description:
 */
public class MicroServiceInterceptor extends SaInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {

            // 这里必须确保 handler 是 HandlerMethod 类型时，才能进行注解鉴权
            if (isAnnotation && handler instanceof HandlerMethod) {

                // 获取此请求对应的 Method 处理函数
                Method method = ((HandlerMethod) handler).getMethod();

                // 如果此 Method 或其所属 Class 标注了 @SaIgnore，则忽略掉鉴权
                if (SaStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) {
                    // 注意这里直接就退出整个鉴权了，最底部的 auth.run() 路由拦截鉴权也被跳出了
                    return true;
                }

                // 如果此 Method 或其所属 Class 标注了 @SaInterior
                // 则只有存在内部调用令牌才可以放行
                if (SaStrategy.instance.isAnnotationPresent.apply(method, SaInterior.class)) {
                    String header = SaHolder.getRequest().getHeader(TokenConstant.FILTER_KEY_NAME);
                    if (!Objects.equals(header, TokenConstant.FILTER_KEY_VALUE)) {
                        throw new ServiceException(HttpCodeEnum.NO_OPERATOR_AUTH, "外部用户不允许访问内部服务！");
                    }
                    return true;
                }

                // 如果此 Method 或其所属 Class 标注了 @SaInteriorOrElse
                // 则为内部调用时放行,外部调用时校验权限
                // 需要搭配权限校验注解配合使用
                if (SaStrategy.instance.isAnnotationPresent.apply(method, SaInteriorOrElse.class)) {
                    String header = SaHolder.getRequest().getHeader(TokenConstant.FILTER_KEY_NAME);
                    if (Objects.equals(header, TokenConstant.FILTER_KEY_VALUE)) {
                        return true;
                    }
                }

                // 执行注解鉴权
                SaStrategy.instance.checkMethodAnnotation.accept(method);
            }

            // Auth 路由拦截鉴权校验
            auth.run(handler);

        } catch (StopMatchException e) {
            // StopMatchException 异常代表：停止匹配，进入Controller

        } catch (BackResultException e) {
            // BackResultException 异常代表：停止匹配，向前端输出结果
            // 		请注意此处默认 Content-Type 为 text/plain，如果需要返回 JSON 信息，需要在 back 前自行设置 Content-Type 为 application/json
            // 		例如：SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
            if (response.getContentType() == null) {
                response.setContentType("text/plain; charset=utf-8");
            }
            response.getWriter().print(e.getMessage());
            return false;
        }

        // 通过验证
        return true;
    }
}
